import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;

public class Line extends DrawObject
{
    // DrawObject abilities:
    @Override
    public boolean IsLine()
    {
        return true;
    }

    @Override
    public boolean CanBeMovedByUser()
    {
        return false;
    }

    @Override
    public boolean CanBeSelectedByUser()
    {
        return true;
    }

    @Override
    public boolean CanBeDeletedByUser()
    {
        return true;
    };

    @Override
    public boolean CanBeExcitedByUser()
    {
        return false;
    };
    // end of DrawObject abilities

    private DrawObject StartDrawObject;
    private DrawObject EndDrawObject;

    public Line(DrawObject StartDrawObject, DrawObject EndDrawObject)
    {
        SetPos(new Point(0, 0)); // dummy Pos and Size, drawn with StartDrawObject and EndDrawObject information only
        SetSize(new Point(0, 0)); // dummy Pos and Size, drawn with StartDrawObject and EndDrawObject information only
        InitializeExcitement(ExcitementOnceMilliseconds);

        this.StartDrawObject = StartDrawObject;
        this.EndDrawObject = EndDrawObject;
    };

    private double DistanceToPoint(Point pt1, Point pt2, Point pt3)
    {
        // maybe a bit complicated but better understandable
        // (see website) and works well

        int Minx = 0;
        int Maxx = 0;

        if (pt1.x <= pt2.x)
        {
            Minx = pt1.x;
            Maxx = pt2.x;
        }
        if (pt1.x >= pt2.x)
        {
            Minx = pt2.x;
            Maxx = pt1.x;
        }

        int Miny = 0;
        int Maxy = 0;

        if (pt1.y <= pt2.y)
        {
            Miny = pt1.y;
            Maxy = pt2.y;
        }
        if (pt1.y >= pt2.y)
        {
            Miny = pt2.y;
            Maxy = pt1.y;
        }

        if ((Maxx - Minx < 50 || (pt3.x >= Minx && pt3.x <= Maxx)) && (Maxy - Miny < 50 || pt3.y >= Miny && pt3.y <= Maxy))
        {
            // https://studyflix.de/mathematik/hohe-dreieck-berechnen-4759, altered

            double c = Math.sqrt((pt2.x - pt1.x) * (pt2.x - pt1.x) + (pt2.y - pt1.y) * (pt2.y - pt1.y));
            double a = Math.sqrt((pt3.x - pt1.x) * (pt3.x - pt1.x) + (pt3.y - pt1.y) * (pt3.y - pt1.y));
            double b = Math.sqrt((pt2.x - pt3.x) * (pt2.x - pt3.x) + (pt2.y - pt3.y) * (pt2.y - pt3.y));

            double s = 0.5 * (a + b + c);

            double hc = 2.0 / c * Math.sqrt(s * (s - a) * (s - b) * (s - c));

            return hc;
        }
        else
        {
            return Double.MAX_VALUE;
        }
    }

    @Override
    public void Draw(Graphics g)
    {
        if (!(IsWithinWindowBounds(this, 0)))
            return;

        // draw single line
        if (IsHighlighted || IsPartOfMultiSelection)
            SetColor(g, Color.GREEN);
        else if (IsCommentField)
            SetColor(g, GetExcitementColor(Color.BLUE));
        else
            SetColor(g, GetExcitementColor(Color.RED));

        int LineStartPosx = StartDrawObject.Pos.x + StartDrawObject.Size.x / 2;
        int LineStartPosy = StartDrawObject.Pos.y + StartDrawObject.Size.y / 2;
        int LineEndPosx = EndDrawObject.Pos.x + EndDrawObject.Size.x / 2;
        int LineEndPosy = EndDrawObject.Pos.y + EndDrawObject.Size.y / 2;

        if (IsCommentField)
            DrawThickLine(
                // if changing this (draw to CENTER), update also GetDistanceToPoint()!
                g, LineStartPosx, LineStartPosy, LineEndPosx, LineEndPosy
            );
        else
            DrawLine(
                // if changing this (draw to CENTER), update also GetDistanceToPoint()!
                g, LineStartPosx, LineStartPosy, LineEndPosx, LineEndPosy
            );

        // draw a little rect as sign for orientation (flow is conducted only in one direction)
        if (!(IsCommentField))
        {
            double Factor = 0.8;

            FillRect(g, (int) (LineStartPosx + (LineEndPosx - LineStartPosx) * Factor - 1), (int) (LineStartPosy + (LineEndPosy - LineStartPosy) * Factor - 1), 3, 3);
        }
    }

    public double GetDistanceToPoint(Point P)
    {
        // ATTENTION: Line goes into CENTER of [Start/End]DrawObject!
        // We NEED to take this into account or Lines are not selected
        // precisely (tested)!

        return DistanceToPoint(
            new Point(StartDrawObject.Pos.x + StartDrawObject.Size.x / 2, StartDrawObject.Pos.y + StartDrawObject.Size.y / 2), new Point(EndDrawObject.Pos.x + EndDrawObject.Size.x / 2, EndDrawObject.Pos.y + EndDrawObject.Size.y / 2), P
        );
    }

    public DrawObject GetEndDrawObject()
    {
        return EndDrawObject;
    }

    public DrawObject GetStartDrawObject()
    {
        return StartDrawObject;
    }

    public void SetEndDrawObject(DrawObject EndDrawObjectNew)
    {
        if (EndDrawObjectNew != null)
            EndDrawObject = EndDrawObjectNew;
        else
            System.out.println("error in Line.SetEndrawObject(): passed value not useful!");
    }

    public void SetStartDrawObject(DrawObject StartDrawObjectNew)
    {
        if (StartDrawObjectNew != null)
            StartDrawObject = StartDrawObjectNew;
        else
            System.out.println("error in Line.SetStartDrawObject(): passed value not useful!");
    }
}
